import cn.bugstack.mybatis.dao.IUserDao04;
import cn.bugstack.mybatis.io.Resource;
import cn.bugstack.mybatis.po.User;
import cn.bugstack.mybatis.reflection.MetaObject;
import cn.bugstack.mybatis.reflection.SystemMetaObject;
import cn.bugstack.mybatis.session.SqlSession;
import cn.bugstack.mybatis.session.SqlSessionFactory;
import cn.bugstack.mybatis.session.SqlSessionFactoryBuilder;
import com.alibaba.fastjson.JSON;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ApiTest {
    private static final Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_SqlSessionFactory() throws Exception {
        // 1. 从SqlSessionFactory中获取SqlSession
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resource.getResourceAsReader("mybatis-config-datasource.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSqlSession();

        // 2. 获取映射器对象
        IUserDao04 userDao = sqlSession.getMapper(IUserDao04.class);

        // 3. 测试验证

        User user = userDao.queryUserInfoById(1L);
        logger.info("测试结果：{}", JSON.toJSONString(user));

    }

    //xmlStatementBuilder会获取sqlSource 并将其放到mappedStatement
    //SqlSource会解析parameterMappings也会制造BoundSql BoundSql有ParameterMappings
    //sqlSession使用执行器构建statementHandler执行语句 提供boundSql
    //statementHandler构建parameterHandler
    //parameterHandler使用parameterMappings处理参数 通过参数调用typeHandler为statement设置参数 接口方法参数为User #{}里是Use属性 调用MetaObject.getValue(propertyName)获取属性值
    //构建语句执行


    @Test
    public void test_queryUserInfo() throws Exception {
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resource.getResourceAsReader("mybatis-config-datasource.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSqlSession();

        IUserDao04 userDao = sqlSession.getMapper(IUserDao04.class);
        User users = userDao.queryUserInfo(new User(1L, "10001"));
//        User user = userDao.queryInfoByIdAndName(1L,"10001");
        logger.info("测试结果：{}", JSON.toJSONString(users));
    }

    @Test
    public void test_Reflect(){
        Teacher teacher = new Teacher();
        List<Teacher.Student> list = new ArrayList<>();
        list.add(new Teacher.Student());
        Teacher.Student student = list.get(0);
        student.setId("001");
        teacher.setName("小傅哥");
        teacher.setStudents(list);

        MetaObject metaObject = SystemMetaObject.forObject(teacher);

        logger.info("getGetterNames：{}", JSON.toJSONString(metaObject.getGetterNames()));
        logger.info("getSetterNames：{}", JSON.toJSONString(metaObject.getSetterNames()));
        logger.info("name的get方法返回值：{}", JSON.toJSONString(metaObject.getGetterType("name")));
        logger.info("students的set方法参数值：{}", JSON.toJSONString(metaObject.getGetterType("students")));
        logger.info("name的hasGetter：{}", metaObject.hasGetter("name"));
        logger.info("student.id（属性为对象）的hasGetter：{}", metaObject.hasGetter("student.id"));
        metaObject.getValue("name");
        metaObject.getValue("students[0].id");
        logger.info("获取name的属性值：{}", metaObject.getValue("students[0].id"));
        logger.info("获取name的属性值：{}", metaObject.getValue("name"));
        // 重新设置属性值
        metaObject.setValue("name", "小白");
        logger.info("设置name的属性值：{}", metaObject.getValue("name"));
        // 设置属性（集合）的元素值
        metaObject.setValue("students[0].id", "001");
        logger.info("获取students集合的第一个元素的属性值：{}", JSON.toJSONString(metaObject.getValue("students[0].id")));
        logger.info("对象的序列化：{}", JSON.toJSONString(teacher));
    }
    static class Teacher {

        private String name;

        private double price;

        private List<Student> students;

        private Student student;

        public static class Student {

            private String id;

            public String getId() {
                return id;
            }

            public void setId(String id) {
                this.id = id;
            }
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public double getPrice() {
            return price;
        }

        public void setPrice(double price) {
            this.price = price;
        }

        public List<Student> getStudents() {
            return students;
        }

        public void setStudents(List<Student> students) {
            this.students = students;
        }

        public Student getStudent() {
            return student;
        }

        public void setStudent(Student student) {
            this.student = student;
        }
    }


    @Test
    public void test_generic(){
        List<User> a = new ArrayList<>();
        Class<?> returnType = getReturnType(String[].class);
    }
    private Class<?> getReturnType(Class<?> returnType){
        if (Collection.class.isAssignableFrom(returnType)){
            //获取方法泛型返回类型
            //a. List<User>
            Type returnTypeParameter = returnType.getGenericSuperclass();
            if (returnTypeParameter instanceof ParameterizedType){
                //getActualTypeArguments() 方法返回一个 Type 数组，表示参数化类型的实际类型参数。
                //例如，对于 List<String>，getActualTypeArguments() 将返回一个包含 String.class 的数组
                //a. {User.class} (Map会使数组有两个元素
                Type[] actualTypeArguments = ((ParameterizedType) returnTypeParameter).getActualTypeArguments();
                //确保有一个类型参数
                if (actualTypeArguments != null && actualTypeArguments.length == 1){
                    returnTypeParameter = actualTypeArguments[0];
                    //如果是类直接返回
                    //a. returnType = User.class
                    if (returnTypeParameter instanceof Class){
                        returnType = (Class<?>) returnTypeParameter;
                    } else if (returnTypeParameter instanceof ParameterizedType) {
                        // 获取原始类型
                        returnType = (Class<?>) ((ParameterizedType) returnTypeParameter).getRawType();
                        //如果是泛型数组
                    } else if (returnTypeParameter instanceof GenericArrayType) {
                        //List<User[]>走到这 返回User[].class
                        // 获取组件类型
                        Class<?> componentType = (Class<?>) ((GenericArrayType) returnTypeParameter).getGenericComponentType();
                    }
                }
            }
        }
        return returnType;
    }
}
